﻿#pragma execution_character_set("utf-8")
#ifndef SPECTROMETERDATA_H
#define SPECTROMETERDATA_H
#include <QVector>
#include <QDataStream>
#include <QDebug>
#include <QJsonObject>
#include <QJsonArray>
#include <QFileInfo>

#include <iostream>
#include "fileutils.h"
#include <mathutils.h>

using namespace std;

class SpectroInfoTag{

public:
    SpectroInfoTag(QList<double> lambda)
    {
        pixelNumber=lambda.count();
        lambdaMin=lambda.first();
        lambdaMax=lambda.last();
        lambdaWidth=lambdaMax-lambdaMin;
        CalcMaxMinInterval(lambdaIntervalMin,lambdaIntervalMax,lambda);
    }

    void CalcMaxMinInterval(double& minRef,double& maxRef,const QList<double> &lambda)
    {
        // 计算相邻元素之间的差值，并找到最大和最小差值
        double maxInterval = 0.0;
        double minInterval = (std::numeric_limits<double>::max)(); // 初始化为一个大值

        for (int i = 1; i < lambda.size(); ++i)
        {
            double interval = lambda[i] - lambda[i - 1];
            maxInterval = (std::max)(maxInterval, interval);
            //不知道为什么使用std::min就会报错
            minInterval = min(minInterval, interval);
        }
        maxRef=maxInterval;
        minRef=minInterval;
    }

    static QStringList GetHeaders()
    {
        return QStringList() << "序列号" << "最小波长[nm]" << "最大波长[nm]"<<"波段宽度[nm]"<<"最小间隔[nm]"<<"最大间隔[nm]"<<"像元数";
    }

    virtual QMap<QString,QVariant> GetMap()
    {
        QMap<QString,QVariant> ret={
            {"序列号",serilID},
            {"最小波长[nm]",lambdaMin},
            {"最大波长[nm]",lambdaMax},
            {"波段宽度[nm]",lambdaWidth},
            {"最小间隔[nm]",lambdaIntervalMin},
            {"最大间隔[nm]",lambdaIntervalMax},
            {"像元数",pixelNumber},
        };
        return ret;
    }
    QString serilID;
    int pixelNumber;
    double lambdaWidth;
    double lambdaMin;
    double lambdaMax;
    double lambdaIntervalMin;
    double lambdaIntervalMax;
    QString samelambdaSpectroID;
};

class AvsMeasResultListInfo:public SpectroInfoTag
{
public:
    int SampleCount;
    AvsMeasResultListInfo(int sampleCount,QList<double> lambda):SpectroInfoTag(lambda)
    {
        SampleCount=sampleCount;
    }

    static QStringList GetHeaders()
    {
        return QStringList() << "序列号" << "最小波长[nm]" << "最大波长[nm]"<<"波段宽度[nm]"<<"最小间隔[nm]"<<"最大间隔[nm]"<<"像元数"<<"光谱数";
    }
    QMap<QString, QVariant> GetMap() override
    {
        QMap<QString,QVariant> ret=SpectroInfoTag::GetMap();
        ret.insert("光谱数",SampleCount);
        return ret;
    }
};


//测量时设定的光谱仪参数信息
struct AvsMeasPara {
    AvsMeasPara()
    {
        integrationTime=20;
        integrationDelay=2;
        NrAverages=2;
        triggerMode=1;
        triggerSource=0;
        isMasterChannel=false;
    }

    float integrationTime;           //积分持续时间
    unsigned int integrationDelay;   //积分延时,最小时钟周期为20.83ns，此处延时为时钟周期个数
    unsigned int NrAverages;         //平均次数，每NrAverages个扫描显示一次光谱
    unsigned char triggerMode;       //触发模式，软件触发和硬件触发0=SoftWare 1=Hardware 2=Free Run
    unsigned char triggerSource;     //触发源，(0 =外部触发，1 =同步输入)
    float gain[2];
    bool isMasterChannel;

    // 重载插入运算符
     friend QDebug operator<<(QDebug  dbg, const AvsMeasPara& para) {
         dbg.nospace() << "Integration Time: " << para.integrationTime<<" ";
         dbg.nospace() << "Integration Delay: " << para.integrationDelay<<" ";
         dbg.nospace() << "Number of Averages: " << para.NrAverages<<" ";
         dbg.nospace() << "Trigger Mode: " << static_cast<int>(para.triggerMode)<<" ";
         dbg.nospace() << "Trigger Source: " << static_cast<int>(para.triggerSource);
         return dbg.space();
     }
};

//光谱仪信息
struct AvsInfo {
    QString serial;
    QString friendname;
    QString pcIP;
    int pcPort;
    QString spectrometerIP;
    int spectrometerPort;
    unsigned char status;
};

//测量结果
typedef struct AvsMeasResultTag {

    AvsMeasResultTag()
    {

    }

    AvsMeasResultTag(QList<double> x,QList<double> y)
    {
        for(int i=0;i<x.count();i++)
        {
            resultData.append(QPointF(x.at(i),y.at(i)));
        }
    }

    QList<QPointF> resultData;   //测量点数据
    QString SerialId;

    int Count()
    {
        return resultData.count();
    }

    QPointF At(int index)
    {
        return resultData.at(index);
    }

    double MinXAxis()
    {
        return resultData.first().x();
    }

    double MaxYValue()
    {
        QList<double> y=YValue();
        double max=*std::max_element(y.constBegin(),y.constEnd());
        return max;
    }

    double MaxXAxis()
    {
        return resultData.last().x();
    }

    QList<double> XAxis()
    {
        QList<double> ret;
        for(int i=0;i<resultData.count();i++)
        {
            ret.append(resultData.at(i).x());
        }
        return ret;
    }

    QList<double> YValue()
    {
        QList<double> ret;
        for(int i=0;i<resultData.count();i++)
        {
            ret.append(resultData.at(i).y());
        }
        return ret;
    }

    const QList<QString> GetXString()
    {
        QList<QString> ret;
        for(int i=0;i<resultData.count();i++)
        {
            ret.append(QString("%1").arg(resultData.at(i).x()));
        }
        return ret;
    }

    const QList<QString> GetYString()
    {
        QList<QString> ret;
        for(int i=0;i<resultData.count();i++)
        {
            ret.append(QString("%1").arg(resultData.at(i).y()));
        }
        return ret;
    }

    AvsMeasResultTag GetInterpolation(QList<double> interXAxis)
    {
        AvsMeasResultTag ret;
        QList<double> y=MathUtils::LinearInterpolation(interXAxis,resultData);
        for(int i=0;i<interXAxis.count();i++)
        {
            ret.resultData.append(QPointF(interXAxis.at(i),y.at(i)));
        }
        ret.SerialId=SerialId;
        return ret;
    }

    AvsMeasResultTag GetIntervalInterpolation(double interval)
    {
        double iter=MinXAxis();
        QList<double> axis;
        while(iter<MaxXAxis())
        {
            axis.append(iter);
            iter+=interval;
        }
        QList<double> y=MathUtils::LinearInterpolation(axis,resultData);
//        qDebug()<<y.count();
        AvsMeasResultTag ret(axis,y);
        ret.SerialId=SerialId;
        return ret;
    }
}AvsMeasResult;

class AvsMeasResultList:public QList<AvsMeasResult>
{
public:
    QStringList GetSerialIdList()
    {
      QStringList ret;
      for(int i=0;i<this->count();i++)
      {
          ret.append(this->at(i).SerialId);
      }
      return ret;
    }

    QList<QList<QPointF>> GetItemList()
    {
        QList<QList<QPointF>> ret;
        for(int i=0;i<this->count();i++)
        {
            ret.append(this->at(i).resultData);
        }
        return ret;
    }

    //等间隔插值处理 interval为间隔
    QList<QList<QPointF>> GetIntervalItemList(double interval)
    {
        QList<QList<QPointF>> ret;
        for(int i=0;i<this->count();i++)
        {
            AvsMeasResultTag item=this->at(i);
            ret.append(item.GetIntervalInterpolation(interval).resultData);
            qDebug()<<__FUNCTION__<<__LINE__<<item.GetIntervalInterpolation(interval).resultData.count();
        }

        return ret;
    }

    bool Parase(QString filePath)
    {
        auto csvMat=FileUtils::ReadCsvFile(filePath);
        qDebug()<<__FUNCTION__<<__LINE__<<csvMat.count();
        Parase(csvMat);
        QFileInfo fileInfo(filePath);
        for(auto &item:*this)
        {
            item.SerialId=fileInfo.baseName();
        }
        return true;
    }

    bool Parase(QList<QList<QString>> &mat)
    {
        mat=TransposeMatrix(mat);
        QList<double> xaxis;
        for(int col=0;col<mat.at(0).count();col++)
        {
            xaxis.append(mat.at(0).at(col).toDouble());
        }
        for(int row=1;row<mat.count();row++)
        {
            AvsMeasResult  avsItem;
            for(int col=0;col<mat.at(0).count();col++)
            {
                double x=xaxis.at(col);
                double y=mat.at(row).at(col).toDouble();
                avsItem.resultData.append(QPointF(x,y));
            }
            this->append(avsItem);
        }
        return true;
    }

    bool Save(QString filePath)
    {
        auto matrix=GetStringMatrix();
        return FileUtils::ExportToCsv(matrix,filePath);
    }

    AvsMeasResultList GetInterpolation(QList<double> interAxis)
    {
        AvsMeasResultList ret;
        for(int i=0;i<this->count();i++)
        {
            AvsMeasResult avs=this->at(i);
            AvsMeasResult item=avs.GetInterpolation(interAxis);
            ret.append(item);
        }
        return ret;
    }

    const QList<QList<QString>> GetStringMatrix()
    {
        QList<QList<QString>> ret;
        for(int i=0;i<this->count();i++)
        {
            AvsMeasResult tempItem=this->at(i);
            if(ret.count()==0)
            {
                ret.append(tempItem.GetXString());
            }
            ret.append(tempItem.GetYString());
        }
        //最后进行转置
        return TransposeMatrix(ret);
    }

    int RowCount()
    {
        return this->count();
    }

    int ColumnCount()
    {
        return this->first().resultData.count();
    }

    AvsMeasResultListInfo GetListInfo()
    {
        AvsMeasResultListInfo ret(RowCount(),this->first().XAxis());
        ret.serilID=this->first().SerialId;
        return ret;
    }

    AvsMeasResult Combine()
    {
        AvsMeasResult ret;
        ret.SerialId = at(0).SerialId;
        for(int i=0;i<count();i++)
        {
            auto data = at(i);
            if (data.resultData.isEmpty())
            {
                return ret;
            }
            ret.resultData.append(at(i).resultData);
        }
        return ret;
    }

    AvsMeasResult GetAvaerage()
    {
        QList<QList<QPointF>> lst;
        for(int i=0;i<count();i++)
        {
            lst.append(at(i).resultData);
        }
        QList<QPointF> avg=CalculateAverage(lst);
        AvsMeasResult ret=at(0);
        ret.resultData=avg;
        return ret;
    }

private:
    // 函数用于计算矩阵的转置
    QList<QList<QString>> TransposeMatrix(const QList<QList<QString>>& mat)
    {
        int numRows = mat.size();
        int numCols = mat.first().count();

        QList<QList<QString>> ret;

        for (int i = 0; i < numCols; ++i) {
            QList<QString> row;
            for (int j = 0; j < numRows; ++j) {
                row.append(mat[j][i]);
            }
            ret.append(row);
        }

        return ret;
    }

    QList<QPointF> CalculateAverage(const QList<QList<QPointF>>& resultData) {
        if (resultData.isEmpty()) {
            throw QString("Input data is empty");
        }

        int numSpectra = resultData.size();
        int numPoints = resultData[0].size();

        // Check if all spectra have the same number of points
        for (const QList<QPointF>& spectrum : resultData) {
            if (spectrum.size() != numPoints) {
                throw QString("All spectra must have the same number of points");
            }
        }

        QList<QPointF> averageData;

        for (int i = 0; i < numPoints; ++i) {
            double sumY = 0.0;
            double xValue = resultData[0][i].x();

            for (const QList<QPointF>& spectrum : resultData) {
                sumY += spectrum[i].y();
            }

            double averageY = sumY / numSpectra;
            averageData.append(QPointF(xValue, averageY));
        }

        return averageData;
    }
};

typedef struct SpecificPeakTag{
    QString peakName;
    double peakValue;

    static QList<SpecificPeakTag> ParaseFromJson(QJsonObject obj)
    {
        QList<SpecificPeak> ret;
        obj["Items"].toArray();
        for(auto item:obj["Items"].toArray())
        {
            QJsonObject itemObj=item.toObject();
            SpecificPeak peak;
            peak.peakName=itemObj["Name"].toString();
            peak.peakValue=itemObj["Value"].toDouble();
            ret.append(peak);
        }
        return ret;
    }
} SpecificPeak;

typedef struct SpectroPMParaTag{
    QString spectorName;
    SpecificPeak perfectPeakInfo;
    double realPeak;
    double distinguishability;
    double realPeakOffset;
    double relativePeakOffset;
    double normalizeValue;
    double R2;

    static QStringList GetHeaders()
    {
        QStringList headers;
        headers<< "序列号" << "谱线名称" << "特征普线[nm]"<<"实际波长[nm]"<<"分辨率[nm]"<<"实际偏差[nm]"<<"相对偏差[%]"<<"归一化强度"<<"拟合系数R2";
        return headers;
    }

    QMap<QString,QVariant> GetMap()
    {
        QMap<QString,QVariant> ret{
            {"序列号",spectorName},
            {"谱线名称",perfectPeakInfo.peakName},
            {"特征普线[nm]",GetFromat(perfectPeakInfo.peakValue)},
            {"实际波长[nm]",GetFromat(realPeak)},
            {"分辨率[nm]",GetFromat(distinguishability)},
            {"实际偏差[nm]",GetFromat(realPeakOffset)},
            {"相对偏差[%]",GetFromat(relativePeakOffset)},
            {"归一化强度",GetFromat(normalizeValue)},
            {"拟合系数R2",GetFromat(R2)}
        };
        return ret;
    }

    double GetFromat(double input,int digit=3)
    {
        QString number=QString::number(input,'f',digit);
        return number.toDouble();
    }

} SpectroPMPara;

typedef struct SpectroRSDTag{
    QString spectorName;
    SpecificPeak perfectPeakInfo;
    double realPeak;
    double normalizeValue;
    double intensityRSD;

} SpectroRSD;

typedef struct SpectrumEfficiencyTag{

    SpectrumEfficiencyTag()
    {
        //不初始化会造成validNumber不为0
        totalNumber=0;
        validNumber=0;
        channel=0;
        SerialId="";
    }

    int totalNumber;
    int validNumber;
    int channel;
    QString SerialId;

    double GetValidRatio()
    {
        if(totalNumber==0)
        {
            return 0;
        }

        double val=((double)validNumber)/((double)totalNumber);
        // 将double格式化为保留两位小数的字符串
        QString formattedValue = QString::number(val, 'f', 4);
        return formattedValue.toDouble();
    }

    QMap<QString,QVariant> GetMap()
    {
//        QString val=QString::number(GetValidRatio()*100,2);
        QMap<QString,QVariant> ret{
            {"序列号",SerialId},
            {"通道",channel},
            {"匹配点数",totalNumber},
            {"满足阈值数",validNumber},
//            {"满足率[%]",QString::number(GetValidRatio()*100,'f',2)},
            {"满足率[%]",GetValidRatio()*100},
            {"Test","占位符"}
        };
        return ret;
    }

    static QStringList GetHeaders()
    {
       QStringList ret;
       ret<<"序列号"<<"通道"<<"匹配点数"<<"满足阈值数"<<"满足率[%]";
       return ret;
    }
}SpectrumEfficiency;

#endif // SPECTROMETERDATA_H
